home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / unixcpio.gz / unixnet.cpio / smtpcli.c < prev    next >
C/C++ Source or Header  |  1994-07-11  |  21KB  |  1,003 lines

  1.  
  2. /*
  3.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  4.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  5.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  6.  *    Permission granted for non-commercial copying and use, provided
  7.  *    this notice is retained.
  8.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  9.  *    also rebuilt locking mechanism
  10.  *    Limit on max simultaneous sessions, reuse of connections - 12/87 NN2Z
  11.  *    Added return of mail to sender as well as batching of commands 1/88 nn2z
  12.  */
  13. #include <stdio.h>
  14. #if    (!ATARI_ST || LATTICE)
  15. #include <fcntl.h>
  16. #endif
  17. #include <time.h>
  18. #ifdef UNIX
  19. #include <sys/types.h>
  20. #include <memory.h>
  21. #include <string.h>
  22. #endif
  23. #include "global.h"
  24. #include "netuser.h"
  25. #include "mbuf.h"
  26. #include "timer.h"
  27. #include "tcp.h"
  28. #include "smtp.h"
  29. #include "trace.h"
  30. #include "cmdparse.h"
  31.  
  32. #ifdef    BSD
  33. char *sprintf();
  34. #endif
  35.  
  36. extern int16 lport;            /* local port placeholder */
  37. extern int32 resolve();
  38. static struct timer smtpcli_t;
  39. int32 gateway;
  40.  
  41. #ifdef SMTPTRACE
  42. int16    smtptrace = 0;            /* used for trace level */
  43. int dosmtptrace();
  44. #endif
  45.  
  46. int16    smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  47. int16    smtpsessions = 0;        /* number of client connections
  48.                     * currently open */
  49. int16    smtpmode = 0;
  50.  
  51. static struct smtp_cb *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  52.  
  53. static char quitcmd[] = "QUIT\r\n";
  54. static char eom[] = "\r\n.\r\n";
  55.  
  56. int smtptick(),dogateway(),dosmtpmaxcli(),mlock(),dotimer(),nextjob();
  57. int setsmtpmode(),sendwindow();
  58. void quit(),abort_trans(),retmail(),sendit(),del_session(),del_job();
  59. void execjobs(),smtp_transaction(),logerr();
  60. struct smtp_cb *newcb(),*lookup();
  61. struct smtp_job *setupjob();
  62.  
  63. struct cmds smtpcmds[] = {
  64.     "gateway",    dogateway,    0,    NULLCHAR,    NULLCHAR,
  65.     "mode",        setsmtpmode,    0,    NULLCHAR,    NULLCHAR,
  66.     "kick",        smtptick,    0,    NULLCHAR,    NULLCHAR,
  67.     "maxclients",    dosmtpmaxcli,    0,    NULLCHAR,    NULLCHAR,
  68.     "timer",    dotimer,    0,    NULLCHAR,    NULLCHAR,
  69. #ifdef SMTPTRACE
  70.     "trace",    dosmtptrace,    0,    NULLCHAR,    NULLCHAR,
  71. #endif
  72.     NULLCHAR,    NULLFP,        0,    
  73.     "subcommands: gateway kick maxclients timer trace",
  74.         NULLCHAR,
  75. };
  76.  
  77. dosmtp(argc,argv)
  78. int argc;
  79. char *argv[];
  80. {
  81.     return subcmd(smtpcmds,argc,argv);
  82. }
  83.  
  84. static int
  85. dosmtpmaxcli(argc,argv)
  86. int argc;
  87. char *argv[];
  88. {
  89.     int x;
  90.     if (argc < 2)
  91.         printf("%d\n",smtpmaxcli);
  92.     else {
  93.         x = atoi(argv[1]);
  94.         if (x > MAXSESSIONS)
  95.             printf("max clients must be <= %d\n",MAXSESSIONS);
  96.         else
  97.             smtpmaxcli = x;
  98.     }
  99.     return 0;
  100. }
  101.  
  102. static int
  103. setsmtpmode(argc,argv)
  104. int argc;
  105. char *argv[];
  106. {
  107.     if (argc < 2) {
  108.         printf("smtp mode: %s\n",
  109.             (smtpmode & QUEUE) ? "queue" : "route");
  110.     } else {
  111.         switch(*argv[1]) {
  112.         case 'q':
  113.             smtpmode |= QUEUE;
  114.             break;
  115.         case 'r':
  116.             smtpmode &= ~QUEUE;
  117.             break;
  118.         default:
  119.             printf("Usage: smtp mode [queue | route]\n");
  120.             break;
  121.         }
  122.     }
  123.     return 0;
  124. }
  125. static int
  126. dogateway(argc,argv)
  127. int argc;
  128. char *argv[];
  129. {
  130.     char *inet_ntoa();
  131.     int32 n;
  132.     extern char badhost[];
  133.  
  134.     if(argc < 2){
  135.         printf("%s\n",inet_ntoa(gateway));
  136.     } else if((n = resolve(argv[1])) == 0){
  137.         printf(badhost,argv[1]);
  138.         return 1;
  139.     } else
  140.         gateway = n;
  141.     return 0;
  142. }
  143.  
  144. #ifdef SMTPTRACE
  145. static int
  146. dosmtptrace(argc,argv)
  147. int argc;
  148. char *argv[];
  149. {
  150.     if (argc < 2)
  151.         printf("%d\n",smtptrace);
  152.     else 
  153.         smtptrace = atoi(argv[1]);
  154.     return 0;
  155. }
  156. #endif
  157.  
  158. /* Set outbound spool poll interval */
  159. static int
  160. dotimer(argc,argv)
  161. int argc;
  162. char *argv[];
  163. {
  164.     int smtptick();
  165.  
  166.     if(argc < 2){
  167.         printf("%lu/%lu\n",
  168.         (smtpcli_t.start - smtpcli_t.count)/(1000/MSPTICK),
  169.         smtpcli_t.start/(1000/MSPTICK));
  170.         return 0;
  171.     }
  172.     smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  173.     smtpcli_t.arg = NULLCHAR;        /* dummy value */
  174.     smtpcli_t.start = atoi(argv[1])*(1000/MSPTICK);    /* set timer duration */
  175.     start_timer(&smtpcli_t);        /* and fire it up */
  176.     return 0;
  177. }
  178.  
  179. /* this is the routine that gets called every so often to do outgoing mail
  180.    processing */
  181. int
  182. smtptick()
  183. {
  184.     register struct smtp_cb *cb;
  185.     struct smtp_job *jp;
  186.     struct list *ap;
  187.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  188.     char    from[LINELEN], to[LINELEN];
  189.     char *cp, *cp1;
  190.     int32 destaddr;
  191.     FILE *wfile;
  192.  
  193. #ifdef SMTPTRACE
  194.     if (smtptrace > 5) {
  195.         printf("smtp daemon entered\n");
  196.         fflush(stdout);
  197.     }
  198. #endif
  199.     for(filedir(mailqueue,0,wfilename);wfilename[0] != '\0';
  200.         filedir(mailqueue,1,wfilename)){
  201.  
  202.         /* save the prefix of the file name which it job id */
  203.         cp = wfilename;
  204.         cp1 = prefix;
  205.         while (*cp && *cp != '.')
  206.             *cp1++ = *cp++;
  207.         *cp1 = '\0';
  208.  
  209.         /* lock this file from the smtp daemon */
  210.         if (mlock(mailqdir,prefix))
  211.             continue;
  212.  
  213.         sprintf(tmpstring,"%s/%s",mailqdir,wfilename);
  214.         if ((wfile = fopen(tmpstring,"r")) == NULLFILE) {
  215.             /* probably too many open files */
  216.             (void) rmlock(mailqdir,prefix);
  217.             /* continue to next message. The failure
  218.             * may be temporary */
  219.             continue;
  220.         }
  221.  
  222.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  223.         rip(tmpstring);
  224.  
  225.         if ((destaddr = mailroute(tmpstring)) == 0) {
  226.             fclose(wfile);
  227.             printf("** smtp: Unknown address %s\n",tmpstring);
  228.             fflush(stdout);
  229.             (void) rmlock(mailqdir,prefix);
  230.             continue;
  231.         }
  232.  
  233.         if ((cb = lookup(destaddr)) == NULLCB) {
  234.             /* there are enough processes running already */
  235.             if (smtpsessions >= smtpmaxcli) {
  236. #ifdef SMTPTRACE
  237.                 if (smtptrace) {
  238.                     printf("smtp daemon: too many processes\n");
  239.                     fflush(stdout);
  240.                 }
  241. #endif
  242.                 fclose(wfile);
  243.                 (void) rmlock(mailqdir,prefix);
  244.                 break;
  245.             }
  246.             if ((cb = newcb()) == NULLCB) {
  247.                 fclose(wfile);
  248.                 (void) rmlock(mailqdir,prefix);
  249.                 break;
  250.             } 
  251.             cb->ipdest = destaddr;
  252.         } else {
  253.             /* This system is already is sending mail lets not
  254.             * interfere with its send queue.
  255.             */
  256.             if (cb->state != CLI_INIT_STATE) {
  257.                 fclose(wfile);
  258.                 (void) rmlock(mailqdir,prefix);
  259.                 continue;
  260.             }
  261.         }
  262.  
  263.         (void) fgets(from,LINELEN,wfile);    /* read from */
  264.         rip(from);
  265.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  266.             fclose(wfile);
  267.             (void) rmlock(mailqdir,prefix);
  268.             del_session(cb);
  269.             break;
  270.         }
  271.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  272.             rip(to);
  273.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  274.                 fclose(wfile);
  275.                 del_session(cb);
  276.             }
  277.         }
  278.         fclose(wfile);
  279. #ifdef SMTPTRACE
  280.         if (smtptrace > 1) {
  281.             printf("queue job %s From: %s To:",prefix,from);
  282.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  283.                 printf(" %s",ap->val);
  284.             printf("\n");
  285.             fflush(stdout);
  286.         }
  287. #endif
  288.     }
  289.  
  290.     /* start sending that mail */
  291.     execjobs();
  292.  
  293.     /* Restart timer */
  294.     start_timer(&smtpcli_t);
  295. }
  296.  
  297. /* this is the master state machine that handles a single SMTP transaction */
  298. void
  299. smtp_transaction(cb)
  300. register struct smtp_cb *cb;
  301. {
  302.     void smtp_cts();
  303.     register char reply;
  304.     register struct list *tp;
  305.     int16 cnt;
  306.     struct mbuf *bp,*bpl;
  307.     char tbuf[LINELEN];
  308.     int rcode;
  309.  
  310. #ifdef SMTPTRACE
  311.     if (smtptrace > 5) 
  312.         printf("smtp_transaction() enter state=%u\n",cb->state);
  313.     if (smtptrace) {
  314.         printf("%s\n",cb->buf);
  315.         fflush(stdout);
  316.     }
  317. #endif
  318.     /* Another line follows; ignore this one */
  319.     if(cb->buf[0] == '0' || cb->buf[3] == '-')
  320.         return;
  321.  
  322.     reply = cb->buf[0];
  323.     rcode = atoi(cb->buf);
  324.  
  325.     /* if service shuting down */
  326.     if (rcode == 421) {
  327.         quit(cb);
  328.         return;
  329.     }
  330.  
  331.     switch(cb->state) {
  332.     case CLI_OPEN_STATE:
  333.         if (reply != '2')
  334.             quit(cb);
  335.         else {
  336.             cb->state = CLI_HELO_STATE;
  337.             sendit(cb,"HELO %s\r\nMAIL FROM:<%s>\r\n",
  338.             hostname,cb->jobq->from);
  339.         }
  340.         break;
  341.     case CLI_HELO_STATE:
  342.         if (reply != '2')
  343.             quit(cb);
  344.         else 
  345.             cb->state = CLI_MAIL_STATE;
  346.         break;            
  347.     case CLI_MAIL_STATE:
  348.         if (reply != '2')
  349.             quit(cb);
  350.         else {
  351.             cb->state = CLI_RCPT_STATE;
  352.             cb->rcpts = 0;
  353.             bpl = NULLBUF;
  354.             for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  355.                 sprintf(tbuf,"RCPT TO:<%s>\r\n",tp->val);
  356.                 bp = qdata(tbuf,(int16)strlen(tbuf));
  357.                 if (bp == NULLBUF) {
  358.                     free_p(bpl);
  359.                     quit(cb);
  360.                     return;
  361.                 }
  362.                 append(&bpl,bp);
  363.                 cb->rcpts++;
  364. #ifdef SMTPTRACE
  365.                 if (smtptrace) {
  366.                     printf(">>> %s",tbuf);
  367.                     fflush(stdout);
  368.                 }
  369. #endif
  370.             }
  371.             send_tcp(cb->tcb,bpl);
  372.         }
  373.         break;
  374.     case CLI_RCPT_STATE:
  375.         if (reply == '5') {
  376.             logerr(cb);
  377.         } else if (reply == '2') {
  378.             cb->goodrcpt =1;
  379.         } else {
  380.             /* some kind of temporary failure */
  381.             abort_trans(cb);
  382.             break;
  383.         }
  384.         /* if more rcpts stay in this state */
  385.         if (--cb->rcpts != 0)
  386.             break;
  387.  
  388.         /* check for no good rcpt on the list */
  389.         if (cb->goodrcpt == 0) {
  390.             if (cb->errlog != NULLLIST)
  391.                 retmail(cb);
  392.             (void) unlink(cb->wname);    /* unlink workfile */
  393.             (void) unlink(cb->tname);    /* unlink text */
  394.             abort_trans(cb);
  395.             break;
  396.         }
  397.         /* if this file open fails abort */
  398.         if ((cb->tfile = fopen(cb->tname,"r")) == NULLFILE)
  399.             abort_trans(cb);
  400.         else {
  401.             /* optimize for slow packet links by sending
  402.              * DATA cmd and the 1st window of text
  403.              */
  404.             if (cb->tcb->window <= cb->tcb->sndcnt)
  405.                 cnt = 0;
  406.             else
  407.                 cnt = cb->tcb->window - cb->tcb->sndcnt;
  408.             bp = qdata("DATA\r\n",6);
  409.             cb->cts = 1;
  410.             cb->state = CLI_SEND_STATE;
  411.             if (sendwindow(cb,bp,cnt) == EOF)
  412.                 cb->cts = 0;
  413.         }
  414.         break;
  415.     case CLI_SEND_STATE:
  416.         if (reply == '3') {
  417.             cb->state = CLI_UNLK_STATE;
  418.         } else {
  419.             /* change cts to transmit upcall queueing more data */
  420.             cb->cts = 0;
  421.             quit(cb);
  422.         }
  423.         break;
  424.     case CLI_UNLK_STATE:
  425.         /* if a good transfer or permanent failure remove job */
  426.         if (reply == '2' || reply == '5') {
  427.             if (reply == '5')
  428.                 logerr(cb);
  429.             /* close and unlink the textfile */
  430.             if(cb->tfile != NULLFILE) {
  431.                 fclose(cb->tfile);
  432.                 cb->tfile = NULLFILE;
  433.             }
  434.             if (cb->errlog != NULLLIST)
  435.                 retmail(cb);
  436.             (void) unlink(cb->tname);
  437.             (void) unlink(cb->wname);    /* unlink workfile */
  438.             log(cb->tcb,"SMTP sent job %s To: %s From: %s",
  439.             cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  440.         }
  441.         if (nextjob(cb)) {
  442.             cb->state = CLI_MAIL_STATE;
  443.             sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  444.         } else 
  445.             /* the quit sent already in smtp_cts */
  446.             cb->state = CLI_QUIT_STATE;
  447.         break;
  448.     case CLI_IDLE_STATE:    /* used after a RSET and more mail to send */
  449.         if (reply != '2')
  450.             quit(cb);
  451.         else {
  452.             cb->state = CLI_MAIL_STATE;
  453.             sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  454.         }
  455.         break;            
  456.     case CLI_QUIT_STATE:
  457.         break;
  458.     }
  459. }
  460.  
  461. /* abort the currrent job.
  462.  * If more work exists set up the next job if
  463.  * not then shut down.
  464. */
  465. static void
  466. abort_trans(cb)
  467. register struct smtp_cb *cb;
  468. {
  469.     if(cb->tfile != NULLFILE) {
  470.         fclose(cb->tfile);
  471.         cb->tfile = NULLFILE;
  472.     }
  473.     if (nextjob(cb)) {
  474.         sendit(cb,"RSET\r\n");
  475.         cb->state = CLI_IDLE_STATE;
  476.     } else 
  477.         quit(cb);
  478. }
  479.  
  480. /* close down link after a failure */
  481. static void
  482. quit(cb)
  483. struct smtp_cb *cb;
  484. {
  485.     cb->state = CLI_QUIT_STATE;
  486.     sendit(cb,quitcmd);        /* issue a quit command */
  487.     close_tcp(cb->tcb);        /* close up connection */
  488. }
  489.  
  490. /* smtp receiver upcall routine.  fires up the state machine to parse input */
  491. static
  492. void
  493. smtp_rec(tcb,cnt)
  494. struct tcb *tcb;
  495. int16 cnt;
  496. {
  497.     register struct smtp_cb *cb;
  498.     char *inet_ntoa();
  499.     char c;
  500.     struct mbuf *bp;
  501.  
  502. #ifdef SMTPTRACE
  503.     if (smtptrace > 7)  {
  504.         printf("smtp_rec called\n");
  505.         fflush(stdout);
  506.     }
  507. #endif
  508.     cb = (struct smtp_cb *)tcb->user;    /* point to our struct */
  509.     recv_tcp(tcb,&bp,cnt);    /* suck up chars from low level routine */
  510.  
  511.     /* Assemble input line in buffer, return if incomplete */
  512.     while(pullup(&bp,&c,1) == 1) {
  513.         switch(c) {
  514.         case '\r':    /* strip cr's */
  515.             continue;
  516.         case '\n':    /* line is finished, go do it! */
  517.             cb->buf[cb->cnt] = '\0';
  518.             smtp_transaction(cb);
  519.             cb->cnt = 0;
  520.             break;
  521.         default:    /* other chars get added to buffer */
  522.             if(cb->cnt != LINELEN-1)
  523.                 cb->buf[cb->cnt++] = c;
  524.             break;
  525.         }
  526.     }
  527. }
  528.  
  529. /* smtp transmitter ready upcall routine.  twiddles cts flag */
  530. static 
  531. void
  532. smtp_cts(tcb,cnt)
  533. struct tcb *tcb;
  534. int16 cnt;
  535. {
  536.     register struct smtp_cb *cb;
  537.  
  538. #ifdef SMTPTRACE
  539.     if (smtptrace > 7) {
  540.         printf("smtp_cts called avail %d\n",cnt);
  541.         fflush(stdout);
  542.     }
  543. #endif
  544.     cb = (struct smtp_cb *)tcb->user;    /* point to our struct */
  545.  
  546.     /* don't do anything until/unless we're supposed to be sending */
  547.     if(cb->cts == 0)
  548.         return;
  549.  
  550.     if (sendwindow(cb,NULLBUF,cnt) == EOF)
  551.         cb->cts = 0;
  552. }
  553.  
  554. /* fill the rest of the window with data and send out the eof commands.
  555. * It is done this way to minimize the number of packets sent.
  556. */
  557. static int
  558. sendwindow(cb,ibp,cnt)
  559. register struct smtp_cb *cb;
  560. struct mbuf *ibp;
  561. int16 cnt;
  562. {
  563.     struct mbuf *bpl;
  564.     register struct mbuf *bp;
  565.     char *cp;
  566.     int c;
  567.     
  568.     bpl = ibp;
  569.     if((bp = alloc_mbuf(cnt)) == NULLBUF){
  570.         /* Hard to know what to do here */
  571.         return EOF;
  572.     }
  573.     cp = bp->data;
  574.     while(cnt > 1 && (c = getc(cb->tfile)) != EOF){
  575. #if (UNIX || MAC || AMIGA || ATARI_ST)
  576.         if(c == '\n'){
  577.             *cp++ = '\r';
  578.             bp->cnt++;
  579.             cnt--;
  580.         }
  581. #endif
  582.         *cp++ = c;
  583.         bp->cnt++;
  584.         cnt--;
  585.     }
  586.     append(&bpl,bp);
  587.     if (cnt > 1) {    /* EOF seen */
  588.         fclose(cb->tfile);
  589.         cb->tfile = NULLFILE;
  590.         /* send the end of data character. */
  591.         if (cnt < sizeof(eom) - 1) {
  592.             bp = qdata(eom,5);
  593.             append(&bpl,bp);
  594.             cnt = 0;    /* dont let anyone else in */
  595.         } else {
  596.             memcpy(&bp->data[bp->cnt],eom,sizeof(eom) - 1);
  597.             bp->cnt += sizeof(eom) - 1;
  598.             cnt -= sizeof(eom) - 1;
  599.         }
  600.         /* send the quit in this packet if last job */
  601.         if (cb->jobq->next == NULLJOB) {
  602.             if (cnt < sizeof(quitcmd) - 1) {
  603.                 bp = qdata(quitcmd,sizeof(quitcmd) - 1);
  604.                 append(&bpl,bp);
  605.             } else {
  606.                 memcpy(&bp->data[bp->cnt],
  607.                 quitcmd,sizeof(quitcmd) - 1);
  608.                 bp->cnt += sizeof(quitcmd) - 1;
  609.             }
  610.         }
  611.         send_tcp(cb->tcb,bpl);
  612.         if (cb->jobq->next == NULLJOB)
  613.             close_tcp(cb->tcb);    /* close up connection */
  614.         return EOF;
  615.     } else {
  616.         send_tcp(cb->tcb,bpl);
  617.         return 0;
  618.     }
  619. }
  620.  
  621. /* smtp state change upcall routine. */
  622. /*ARGSUSED*/
  623. static
  624. void
  625. smtp_state(tcb,old,new)
  626. register struct tcb *tcb;
  627. char old,new;
  628. {
  629.     register struct smtp_cb *cb;
  630.     extern char *tcpstates[];
  631.  
  632. #ifdef SMTPTRACE
  633.     if (smtptrace > 7) {
  634.         printf("smtp_state called: %s\n",tcpstates[new]);
  635.         fflush(stdout);
  636.     }
  637. #endif
  638.     cb = (struct smtp_cb *)tcb->user;
  639.     switch(new) {
  640.     case ESTABLISHED:
  641.         cb->state = CLI_OPEN_STATE;    /* shouldn't be needed */
  642.         break;
  643.     case CLOSE_WAIT:
  644.         close_tcp(tcb);            /* shut things down */
  645.         break;
  646.     case CLOSED:
  647.         /* if this close was not done by us ie. a RST */
  648.         if(cb->tfile != NULLFILE)
  649.             fclose(cb->tfile);
  650.         del_session(cb);
  651.         del_tcp(tcb);
  652.         break;
  653.     }
  654. }
  655.  
  656. /* Send message back to server */
  657. /*VARARGS*/
  658. static void
  659. sendit(cb,fmt,arg1,arg2)
  660. struct smtp_cb *cb;
  661. char *fmt,*arg1,*arg2;
  662. {
  663.     struct mbuf *bp;
  664.     char tmpstring[256];
  665.  
  666. #ifdef SMTPTRACE
  667.     if (smtptrace) {
  668.         printf(">>> ");
  669.         printf(fmt,arg1,arg2);
  670.         fflush(stdout);
  671.     }
  672. #endif
  673.     sprintf(tmpstring,fmt,arg1,arg2);
  674.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  675.     send_tcp(cb->tcb,bp);
  676. }
  677.  
  678. /* create mail lockfile */
  679. int
  680. mlock(dir,id)
  681. char *dir,*id;
  682. {
  683.     char lockname[LINELEN];
  684.     int fd;
  685.     /* Try to create the lock file in an atomic operation */
  686.     sprintf(lockname,"%s/%s.lck",dir,id);
  687. #if    (ATARI_ST && !LATTICE)
  688.     if(!access(lockname,0) || (fd = creat(lockname, 0666)) == -1)
  689.         return -1;
  690. #else
  691.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  692.         return -1;
  693. #endif
  694.     close(fd);
  695.     return 0;
  696. }
  697.  
  698. /* remove mail lockfile */
  699. int
  700. rmlock(dir,id)
  701. char *dir,*id;
  702. {
  703.     char lockname[LINELEN];
  704.     sprintf(lockname,"%s/%s.lck",dir,id);
  705.     return(unlink(lockname));
  706. }
  707.  
  708. /* free the message struct and data */
  709. static void
  710. del_session(cb)
  711. register struct smtp_cb *cb;
  712. {
  713.     register struct smtp_job *jp,*tp;
  714.     register int i;
  715.  
  716.     if (cb == NULLCB)
  717.         return;
  718.     for(i=0; i<MAXSESSIONS; i++) 
  719.         if(cli_session[i] == cb) {
  720.             cli_session[i] = NULLCB;
  721.             break;
  722.         }
  723.  
  724.     if(cb->wname != NULLCHAR)
  725.         free(cb->wname);
  726.     if(cb->tname != NULLCHAR)
  727.         free(cb->tname);
  728.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  729.             tp = jp->next;
  730.             del_job(jp);
  731.     }
  732.     del_list(cb->errlog);
  733.     free((char *)cb);
  734.     smtpsessions--;    /* number of connections active */
  735. }
  736.  
  737. void
  738. del_job(jp)
  739. register struct smtp_job *jp;
  740. {
  741.     if ( *jp->jobname != '\0')
  742.         (void) rmlock(mailqdir,jp->jobname);
  743.     if(jp->from != NULLCHAR)
  744.         free(jp->from);
  745.     del_list(jp->to);
  746.     free((char *)jp);
  747. }
  748.  
  749. /* delete a list of list structs */
  750. void
  751. del_list(lp)
  752. struct list *lp;
  753. {
  754.     register struct list *tp, *tp1;
  755.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  756.             tp1 = tp->next;
  757.             if(tp->val != NULLCHAR)
  758.                 free(tp->val);
  759.             free((char *)tp);
  760.     }
  761. }
  762.  
  763. /* return message to sender */
  764. static void
  765. retmail(cb)
  766. struct smtp_cb *cb;
  767. {
  768.     register struct list *lp;
  769.     register FILE *tfile;
  770.     register int c;
  771.     FILE *infile,*tmpfile();
  772.     char *host,*to;
  773.     time_t t,time();
  774. #ifdef SMTPTRACE
  775.     if (smtptrace > 5) {
  776.         printf("smtp job %s returned to sender\n",cb->wname);
  777.         fflush(stdout);
  778.     }
  779. #endif
  780.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  781.     to = cb->jobq->from;
  782.     if (*to == '\0')
  783.         return;
  784.     if ((host = index(to,'@')) == NULLCHAR)
  785.         host = hostname;
  786.     else
  787.         host++;
  788.     if ((infile = fopen(cb->tname,"r")) == NULLFILE)
  789.         return;
  790.     if ((tfile = tmpfile()) == NULLFILE) {
  791.         fclose(infile);
  792.         return;
  793.     }
  794.     time(&t);
  795.     fprintf(tfile,"Date: %s",ptime(&t));
  796.     fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),hostname);
  797.     fprintf(tfile,"From: MAILER-DAEMON@%s\n",hostname);
  798.     fprintf(tfile,"To: %s\n",to);
  799.     fprintf(tfile,"Subject: Failed mail\n\n");
  800.     fprintf(tfile,"  ===== transcript follows =====\n\n");
  801.  
  802.     for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  803.         fprintf(tfile,"%s\n",lp->val);
  804.  
  805.     fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  806.  
  807.     while((c = getc(infile)) != EOF)
  808.         if (putc(c,tfile) == EOF)
  809.             break;
  810.     fclose(infile);
  811.     fseek(tfile,0L,0);
  812.     if ((smtpmode & QUEUE) != 0)
  813.         router_queue(cb->tcb,tfile,"",(struct list *)to);
  814.     else
  815.         queuejob(cb->tcb,tfile,host,to,"");
  816.     fclose(tfile);
  817. }
  818.  
  819. /* look to see if a smtp control block exists for this ipdest */
  820. static struct smtp_cb *
  821. lookup(destaddr)
  822. int32 destaddr;
  823. {
  824.     register int i;
  825.  
  826.     for(i=0; i<MAXSESSIONS; i++) {
  827.         if (cli_session[i] == NULLCB)
  828.             continue;
  829.         if(cli_session[i]->ipdest == destaddr)
  830.             return cli_session[i];
  831.     }
  832.     return NULLCB;
  833. }
  834.  
  835. /* create a new  smtp control block */
  836. static struct smtp_cb *
  837. newcb()
  838. {
  839.     register int i;
  840.     register struct smtp_cb *cb;
  841.  
  842.     for(i=0; i<MAXSESSIONS; i++) {
  843.         if(cli_session[i] == NULLCB) {
  844.             cb = (struct smtp_cb *)calloc(1,sizeof(struct smtp_cb));
  845.             if (cb == NULLCB)
  846.                 return(NULLCB);
  847.             cb->wname = malloc((unsigned)strlen(mailqdir)+JOBNAME);
  848.             if (cb->wname == NULLCHAR) {
  849.                 free((char *)cb);
  850.                 return(NULLCB);
  851.             }
  852.             cb->tname = malloc((unsigned)strlen(mailqdir)+JOBNAME);
  853.             if (cb->tname == NULLCHAR) {
  854.                 free(cb->wname);
  855.                 free((char *)cb);
  856.                 return(NULLCB);
  857.             }
  858.             cb->state = CLI_INIT_STATE;
  859.             cli_session[i] = cb;
  860.             smtpsessions++;    /* number of connections active */
  861.             return(cb);
  862.         }
  863.     }
  864.     return NULLCB;
  865. }
  866.  
  867. static void
  868. execjobs()
  869. {
  870.     struct socket lsocket, fsocket;
  871.     void smtp_rec(), smtp_cts(), smtp_state();
  872.     register struct smtp_cb *cb;
  873.     register int i;
  874.  
  875.     for(i=0; i<MAXSESSIONS; i++) {
  876.         cb = cli_session[i];
  877.         if (cb == NULLCB) 
  878.             continue;
  879.         if(cb->state != CLI_INIT_STATE)
  880.             continue;
  881.  
  882.         sprintf(cb->tname,"%s/%s.txt",mailqdir,cb->jobq->jobname);
  883.         sprintf(cb->wname,"%s/%s.wrk",mailqdir,cb->jobq->jobname);
  884.  
  885.         /* setup the socket */
  886.         fsocket.address = cb->ipdest;
  887.         fsocket.port = SMTP_PORT;
  888.         lsocket.address = ip_addr;    /* our ip address */
  889.         lsocket.port = lport++;        /* next unused port */
  890. #ifdef SMTPTRACE
  891.         if (smtptrace) {
  892.             printf("Trying Connection to %s\n",inet_ntoa(fsocket.address));
  893.             fflush(stdout);
  894.         }
  895. #endif
  896.  
  897.         /* open smtp connection */
  898.         cb->state = CLI_OPEN_STATE;    /* init state placeholder */
  899.         cb->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,tcp_window,
  900.             smtp_rec,smtp_cts,smtp_state,0,(char *)cb);
  901.         cb->tcb->user = (char *)cb;    /* Upward pointer */
  902.     }
  903. }
  904.     
  905. /* add this job to control block queue */
  906. struct smtp_job *
  907. setupjob(cb,id,from)
  908. struct smtp_cb *cb;
  909. char *id,*from;
  910. {
  911.     register struct smtp_job *p1,*p2;
  912.  
  913.     p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
  914.     if (p1 == NULLJOB)
  915.         return NULLJOB;
  916.     p1->from = malloc((unsigned)strlen(from) + 1);
  917.     if (p1->from == NULLCHAR) {
  918.         free((char *)p1);
  919.         return NULLJOB;
  920.     }
  921.     strcpy(p1->from,from);
  922.     strcpy(p1->jobname,id);
  923.     /* now add to end of jobq */
  924.     if ((p2 = cb->jobq) == NULLJOB)
  925.         cb->jobq = p1;
  926.     else {
  927.         while(p2->next != NULLJOB)
  928.             p2 = p2->next;
  929.         p2->next = p1;
  930.     }
  931.     return p1;
  932. }
  933.  
  934. /* called to advance to the next job */
  935. static int
  936. nextjob(cb)
  937. register struct smtp_cb *cb;
  938. {
  939.     register struct smtp_job *jp;
  940.  
  941.  
  942.     jp = cb->jobq->next;
  943.     del_job(cb->jobq);
  944.     if (jp == NULLJOB) {
  945.         cb->jobq = NULLJOB;
  946.         return 0;
  947.     }
  948.     /* remove the error log of previous message */
  949.     del_list(cb->errlog);
  950.     cb->errlog = NULLLIST;
  951.     cb->goodrcpt = 0;
  952.     cb->jobq = jp;
  953.     sprintf(cb->tname,"%s/%s.txt",mailqdir,jp->jobname);
  954.     sprintf(cb->wname,"%s/%s.wrk",mailqdir,jp->jobname);
  955. #ifdef SMTPTRACE
  956.     if (smtptrace > 5) {
  957.         printf("sending job %s\n",jp->jobname);
  958.         fflush(stdout);
  959.     }
  960. #endif
  961.         return 1;
  962.  
  963. }
  964.  
  965.  
  966. /* mail routing funtion. For now just used the hosts file */
  967. int32
  968. mailroute(dest)
  969. char *dest;
  970. {
  971.     int32 destaddr;
  972.  
  973.     /* look up address or use the gateway */
  974.     if ((destaddr = resolve(dest)) == 0)
  975.         if (gateway != 0) 
  976.             destaddr = gateway; /* Use the gateway  */
  977.     return destaddr;
  978.     
  979. }
  980.  
  981. /* save error reply for in error list */
  982. static void
  983. logerr(cb)
  984. struct smtp_cb *cb;
  985. {
  986.     register struct list *lp,*tp;
  987.     if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
  988.         return;
  989.     if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
  990.         free((char *)tp);
  991.         return;
  992.     }
  993.     /* find end of list */
  994.     if ((lp = cb->errlog) == NULLLIST)
  995.         cb->errlog = tp;
  996.     else {
  997.         while(lp->next != NULLLIST)
  998.             lp = lp->next;
  999.         lp->next = tp;
  1000.     }
  1001.     strcpy(tp->val,cb->buf);
  1002. }
  1003.